﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;
using Microsoft.Win32;

using CompilerForC.LexicalAnalysis;
using CompilerForC.SyntaxAnalysis;
using CompilerForC.SyntaxAnalysis.TreeCollection;

namespace Syntax_GUI
{
    class Control
    {
        private CompilerGUI FormRef;
        private Lexer lexer;
        private Parser parser;

        public Control(CompilerGUI FormRef)
        {
            this.FormRef = FormRef;
            this.lexer = new Lexer();
            this.parser = new Parser();
        }

        public void DoLexical()
        {
            string source = this.FormRef.EditorTextBox.Text;
            this.lexer.Tokenize(source);

            this.FormRef.TokenDataGridView.Rows.Clear();
            foreach (Token token in this.lexer.Tables.Tokens)
            {
                this.FormRef.TokenDataGridView.Rows.Add(token.LineNumber, token.Type, token.TableIndex);
            }

            this.FormRef.KeywordsDataGridView.Rows.Clear();
            foreach (KeyValuePair<int, Keyword> keyword in this.lexer.Tables.Keywords)
            {
                this.FormRef.KeywordsDataGridView.Rows.Add(keyword.Key, keyword.Value.Name);
            }

            this.FormRef.OperatorsDataGridView.Rows.Clear();
            foreach (KeyValuePair<int, Operator> oper in this.lexer.Tables.Operators)
            {
                this.FormRef.OperatorsDataGridView.Rows.Add(oper.Key, oper.Value.Name);
            }

            this.FormRef.IdentifierDataGridView.Rows.Clear();
            foreach (KeyValuePair<int, Identifier> identifier in this.lexer.Tables.Identifiers)
            {
                this.FormRef.IdentifierDataGridView.Rows.Add(identifier.Key, identifier.Value.Name);
            }

            this.FormRef.ConstantsDataGridView.Rows.Clear();
            foreach (KeyValuePair<int, Constant> constant in this.lexer.Tables.Constants)
            {
                this.FormRef.ConstantsDataGridView.Rows.Add(constant.Key, constant.Value.Value, constant.Value.Type);
            }

            this.FormRef.LexicalErrorsList.Items.Clear();
            this.FormRef.CumulativeErrorsListBox.Items.Clear();
            string errorLine;
            foreach (LexerError error in this.lexer.Tables.Errors)
            {
                errorLine = "Error (" + error.Code + "): " + error.Description + ", On line: " + error.LineNumber;
                this.FormRef.LexicalErrorsList.Items.Add(errorLine);
                this.FormRef.CumulativeErrorsListBox.Items.Add(errorLine);
            }

        }

        public void DoParse()
        {
            this.FormRef.SyntaxErrorTextBox.Clear();
            this.DoLexical();
            if (this.parser.Parse(this.lexer.Tables))
            {
                   
            }
            else
            {
                string errorLine;
                foreach (SyntaxError err in this.parser.SyntaxErrors)
                {
                    errorLine = "Line: " + err.Line + ", Error: " + err.Description;
                    this.FormRef.SyntaxErrorTextBox.Text += "Line: " + err.Line + ", Error: " + err.Description + "\r\n";
                    this.FormRef.CumulativeErrorsListBox.Items.Add(errorLine);
                }
            }

            try
            {
                string parseTreeFile = String.Concat(Path.GetTempFileName(), ".png");

                this.SaveParseTree(parser.ParseTreeRootNode, parseTreeFile);

                ProcessStartInfo previewProcessInfo = new ProcessStartInfo();

                previewProcessInfo.Verb = "open";
                previewProcessInfo.FileName = parseTreeFile;
                Process.Start(previewProcessInfo);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message, "Syntax Test", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            
        }

        public void SaveParseTree(TreeNode<SyntaxNode> root, string filepath)
        {
            string dotFilePath = Path.GetTempFileName();

            using (StreamWriter sw = new StreamWriter(dotFilePath))
            {
                sw.WriteLine("digraph ParseTree");
                sw.WriteLine("{");

                this.WriteNodeAttributes(sw, root);

                sw.WriteLine();

                this.WriteNodeLinks(sw, root);

                sw.WriteLine("}");
            }

            string dotPath = @"C:\Program Files\Graphviz 2.21\bin\dot.exe";
            Process process = Process.Start(dotPath, String.Format("-Tpng \"{0}\" -o \"{1}\"", dotFilePath, filepath));
            process.WaitForExit();

            File.Delete(dotFilePath);
        }

        public void WriteNodeAttributes(StreamWriter sw, TreeNode<SyntaxNode> parent)
        {
            if (parent.Value.Terminal)
                sw.WriteLine(String.Format("\t{0} [label=\"{1}\", shape=box, style=filled, fillcolor=lightblue, color=black, fontname=Consolas, fontcolor=red];", parent.GetHashCode(), parent.Value.ToString()));
            else
                sw.WriteLine(String.Format("\t{0} [label=\"{1}\", shape=ellipse, style=filled, fillcolor=lightblue color=black, fontname=Consolas, fontcolor=blue];", parent.GetHashCode(), parent.Value.ToString()));

            foreach (TreeNode<SyntaxNode> child in parent.Children)
            {
                this.WriteNodeAttributes(sw, child);
            }
        }

        public void WriteNodeLinks(StreamWriter sw, TreeNode<SyntaxNode> parent)
        {
            foreach (TreeNode<SyntaxNode> child in parent.Children)
            {
                sw.WriteLine(String.Format("\t{0} -> {1};", parent.GetHashCode(), child.GetHashCode()));

                this.WriteNodeLinks(sw, child);
            }
        }
    }
}
